package com.nacrtstudio.webgiftshop.core.dao.impl;

import java.io.Serializable;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Transactional;

import com.nacrtstudio.webgiftshop.core.dao.HibernateDao;

public class HibernateDaoImpl extends HibernateDaoSupport implements HibernateDao<Session>{
	/**
     * Retrieves <code>Session</code> that manages object that will be searched. 
     * 
     * @return session
     */
    public Session provideManager() {
    	return getSessionFactory().getCurrentSession();
    }
    
    @SuppressWarnings("unchecked")
    @Transactional
    public <T> List<T> get(Class<T> searchForType) {
        Session session = provideManager();
        Criteria criteria = session.createCriteria(searchForType);
        return criteria.list();
    }
    
    @SuppressWarnings("unchecked")
    @Transactional
    public <T> List<T> get(Class<T> searchForType, int firstResult, int maxResults) {
        Session session = provideManager();
        Criteria criteria = session.createCriteria(searchForType);
        criteria.setFirstResult(firstResult);
        criteria.setMaxResults(maxResults);
        return criteria.list();
    }

    @SuppressWarnings("unchecked")
    @Transactional
    public <T> T get(Serializable id, Class<T> searchForType) {
        Session session = provideManager();
        Criteria criteria = session.createCriteria(searchForType);
        criteria.add(Restrictions.idEq(id)).setMaxResults(1);
        return (T)criteria.list().get(0);
    }

    @SuppressWarnings("unchecked")
    @Transactional
    public <T> List<T> get(Class<T> searchForType, T example) {
        Session session = provideManager();
        Criteria criteria = session.createCriteria(searchForType);
        criteria.add(Example.create(example));
        return criteria.list();
    }
    
    @SuppressWarnings("unchecked")
    @Transactional
    public <T> List<T> get(Class<T> searchForType, T example, int firstResult, int maxResults) {
        Session session = provideManager();
        Criteria criteria = session.createCriteria(searchForType);
        criteria.add(Example.create(example));
        criteria.setFirstResult(firstResult);
        criteria.setMaxResults(maxResults);
        return criteria.list();
    }

    @SuppressWarnings("unchecked")
    @Transactional
	public <T> List<T> get(T example) {
        return get((Class<T>)example.getClass(), example);
    }

    @SuppressWarnings("unchecked")
    @Transactional
	public <T> List<T> get(T example, int firstResult, int maxResults) {
        return get((Class<T>)example.getClass(), example, firstResult, maxResults);
    }
    
    @SuppressWarnings("unchecked")
    @Transactional
	public <T> T getByPropertyValue(Class<T> searchForType, String property, String value) {
    	Session session = provideManager();
    	Criteria criteria = session.createCriteria(searchForType);
        return (T) criteria.add(Restrictions.eq(property, value)).uniqueResult();
    }

    @Transactional
    public void save(Object object) {
        Session session = provideManager();
        session.saveOrUpdate(object); 
    }

    @Transactional
    public void delete(Object object) {
        Session session = provideManager();
        session.delete(object);
    }

    @Transactional
    public void delete(Serializable id) {
        Object toBeDeleted = get(id);
        delete(toBeDeleted);
    }

    @Transactional
    public void deleteAll(Class clazz) {
        Session session = provideManager();
        session.delete("from " + clazz.getName());
    }

    @Transactional
    public void flush() {
       Session session = provideManager();
       session.flush();
    }

	@SuppressWarnings("unchecked")
	@Transactional
	public <T> List<T> getByMaxValue(Class<T> class1, String property) {
		Session session = provideManager();
    	Criteria criteria = session.createCriteria(class1);
    	return criteria.addOrder(Order.desc(property)).list();
	}
	@SuppressWarnings("unchecked")
    @Transactional
	public <T> T getByLongValue(Class<T> searchForType, String property,
			Long value) {
		Session session = provideManager();
    	Criteria criteria = session.createCriteria(searchForType);
		return (T) criteria.add(Restrictions.eq(property, value)).uniqueResult();
	}
	
	@SuppressWarnings("unchecked")
    @Transactional
	public <T> List<T> getAllAscSortByProperty(Class<T> searchForType, String property) {
		Session session = provideManager();
    	Criteria criteria = session.createCriteria(searchForType);
		return criteria.addOrder(Order.asc(property)).list();
	}
	
	@SuppressWarnings("unchecked")
    @Transactional
	public <T> List<T> getAllDescSortByProperty(Class<T> searchForType, String property) {
		Session session = provideManager();
    	Criteria criteria = session.createCriteria(searchForType);
		return criteria.addOrder(Order.desc(property)).list();
	}
}
